package com.fishleap.config;

import com.fishleap.io.Resources;
import com.fishleap.pojo.Configuration;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.beans.PropertyVetoException;
import java.io.InputStream;
import java.util.List;
import java.util.Properties;

/**
 * @author zlg
 * @create 2020-04-21 22:51
 * 用来封装解析 xml文件的相关方法
 */
public class XmlConfigBuilder {

    // 定义一个全局的 Configuration对象
    private Configuration configuration;

    // 创建XmlConfigBuilder对象时同时创建configuration对象
    public XmlConfigBuilder() {
        this.configuration = new Configuration();
    }

    public Configuration parseConfiguration(InputStream inputStream) throws DocumentException, PropertyVetoException {
        // 获取document对象
        Document document = new SAXReader().read(inputStream);
        // 获取根元素
        Element rootElement = document.getRootElement();

        // 从rootElement中获取datasource所有 property 标签的元素
        // 参数 "//property"表示当前根节点下所有property元素, xml-apis表达式
        List<Element> propertyList = rootElement.selectNodes("//property");
        // 使用Properties对象封装数据源数据
        Properties properties = new Properties();
        for (Element element : propertyList) {
            properties.setProperty(element.attributeValue("name"),element.attributeValue("value"));
        }
        // 配置数据库连接池根据Properties中的数据源数据,解决频繁创建和释放数据库连接问题
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        comboPooledDataSource.setDriverClass(properties.getProperty("driverClass"));
        comboPooledDataSource.setJdbcUrl(properties.getProperty("jdbcUrl"));
        comboPooledDataSource.setUser(properties.getProperty("user"));
        comboPooledDataSource.setPassword(properties.getProperty("password"));

        // 封装数据源到Configuration对象中
        configuration.setDatasource(comboPooledDataSource);

        // 解析 *mapper.xml
        /**
         * 遇到错误:
         * 1.创建的xmlMapperBuilder对象不能放在循环中,
         *  将所有MapperStatement封装到Configuration对象中
         * 2.调用parseMapper时传入输入流参数,
         *  尽量别传入mapper全路径,做到公用方法(文件路径和流都可以公用)
         */
        List<Element> mapperList = rootElement.selectNodes("//mapper");
        XmlMapperBuilder xmlMapperBuilder = new XmlMapperBuilder(configuration);
        for (Element element : mapperList) {
            String mapperPath = element.attributeValue("resource");
            InputStream is = Resources.getResourceAsStream(mapperPath);
            // 解析mapper文件
            xmlMapperBuilder.parseMapper(is);
        }

        return configuration;
    }

}
